package com.smile.commons.md5;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * MD5加盐加密工具类
 */
public class MD5Util {

    // 盐值长度（推荐至少16字节）
    private static final int SALT_LENGTH = 16;

    /**
     * 生成随机盐值
     * @return Base64编码的盐值字符串
     */
    public static String generateSalt() {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[SALT_LENGTH];
        random.nextBytes(salt);
        return Base64.getEncoder().encodeToString(salt);
    }

    /**
     * MD5加盐加密
     * @param data 原始数据
     * @param salt Base64编码的盐值
     * @return 十六进制格式的加密字符串
     */
    public static String md5WithSalt(String data, String salt) {
        try {
            // 将Base64盐值解码为字节数组
            byte[] saltBytes = Base64.getDecoder().decode(salt);
            return md5WithSalt(data.getBytes(), saltBytes);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException("Invalid salt format", e);
        }
    }

    /**
     * MD5加盐加密（字节数组版）
     * @param data 原始数据字节数组
     * @param salt 盐值字节数组
     * @return 十六进制格式的加密字符串
     */
    private static String md5WithSalt(byte[] data, byte[] salt) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");

            // 添加盐值到摘要计算
            md.update(salt);

            // 添加原始数据
            md.update(data);

            // 完成哈希计算
            byte[] digest = md.digest();

            // 转换为十六进制字符串
            return bytesToHex(digest);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5 algorithm not available", e);
        }
    }

    /**
     * 验证数据是否匹配
     * @param data 原始数据
     * @param salt Base64编码的盐值
     * @param encrypted 加密后的字符串
     * @return 验证结果
     */
    public static boolean verify(String data, String salt, String encrypted) {
        return md5WithSalt(data, salt).equals(encrypted);
    }

    /**
     * 字节数组转十六进制字符串
     */
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    // 测试示例
    public static void main(String[] args) {
        String original = "Hello@123";
        System.out.println("原始数据: " + original);

        // 生成盐值
        String salt = generateSalt();
        System.out.println("生成盐值: " + salt);

        // 加密
        String encrypted = md5WithSalt(original, salt);
        System.out.println("加密结果: " + encrypted);

        // 验证
        System.out.println("验证结果: " + verify(original, salt, encrypted));
        System.out.println("错误验证: " + verify("WrongData", salt, encrypted));
    }
}